package com.nl.gen.core;

import com.nl.gen.config.GenerateConfig;
import com.nl.model.consts.ConstPool;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

/**
 * GenerateUtil.
 *
 * @author zenghao
 */
public class GenerateUtil {

    public static final String MODULE_API = "api";

    public static final String MODULE_SERVICE = "service";

    public static final String MODULE_DAL = "dal";

    private static final String XML_FILE_SUFFIX = ".xml";

    /**
     * 数据库类型和java类型映射.
     */
    private static final Map<String, JavaTypeEnum> TYPE_MAPPING = new HashMap<>();

    static {
        TYPE_MAPPING.put("INT", JavaTypeEnum.Integer);
        TYPE_MAPPING.put("TINYINT", JavaTypeEnum.Integer);
        TYPE_MAPPING.put("SMALLINT", JavaTypeEnum.Integer);
        TYPE_MAPPING.put("BIGINT", JavaTypeEnum.Long);
        TYPE_MAPPING.put("FLOAT", JavaTypeEnum.Float);
        TYPE_MAPPING.put("DOUBLE", JavaTypeEnum.Double);
        TYPE_MAPPING.put("DATETIME", JavaTypeEnum.Date);
        TYPE_MAPPING.put("TIMESTAMP", JavaTypeEnum.Date);
        TYPE_MAPPING.put("BIT", JavaTypeEnum.Boolean);
        TYPE_MAPPING.put("DATE", JavaTypeEnum.Date);
        TYPE_MAPPING.put("TIME", JavaTypeEnum.Date);
        TYPE_MAPPING.put("VARCHAR", JavaTypeEnum.String);
        TYPE_MAPPING.put("TEXT", JavaTypeEnum.String);
        TYPE_MAPPING.put("MEDIUMTEXT", JavaTypeEnum.String);
        TYPE_MAPPING.put("LONGTEXT", JavaTypeEnum.String);
        TYPE_MAPPING.put("CHAR", JavaTypeEnum.String);
        TYPE_MAPPING.put("BLOB", JavaTypeEnum.String);
        TYPE_MAPPING.put("DECIMAL", JavaTypeEnum.BigDecimal);
        TYPE_MAPPING.put("ENUM", JavaTypeEnum.String);
    }

    /**
     * getJavaClass.
     *
     * @param dbType 数据库中数据类型
     * @return JavaTypeEnum
     */
    public static JavaTypeEnum getJavaClass(final String dbType) {
        if (StringUtils.isNotBlank(dbType) && TYPE_MAPPING.containsKey(dbType.toUpperCase())) {
            return TYPE_MAPPING.get(dbType.toUpperCase());
        }
        throw new RuntimeException(String.format("无法找到数据库类型 %s 对应的数据类型,请将该类型对应的转换加入 GenerateUtil.TYPE_MAPPING", dbType));
    }

    /**
     * getPackageName.
     *
     * @param packageName packageName
     * @param moduleName  moduleName
     * @return String
     */
    public static String getPackageName(final String packageName, final String moduleName) {
        if (packageName == null || moduleName == null || moduleName.trim().length() == 0 || packageName.endsWith(moduleName)) {
            return packageName;
        }
        return packageName.concat(ConstPool.DOT).concat(moduleName.replace(ConstPool.DASH, ConstPool.DOT));
    }

    /**
     * 生成文件路径.
     *
     * @param config      代码生成配置
     * @param packageName 包名
     * @param outPath     输出文件信息
     * @return String
     */
    public static String genFilePath(final GenerateConfig config, final String packageName, final String outPath) {
        if (outPath.endsWith(XML_FILE_SUFFIX)) {
            return config.getXmlOutPath();
        }
        return config.getOutPath() + File.separator + packageName.replace(ConstPool.DOT, File.separator);
    }

    /**
     * 表名生成类名.
     *
     * @param tableName tableName
     * @return String
     */
    public static String genClassName(final String tableName) {
        return tableName.substring(0, 1).toUpperCase() + underlineToCamelCase(tableName.substring(1));
    }

    /**
     * 下划线，转换为驼峰式.
     *
     * @param underscoreName underscoreName
     * @return String
     */
    public static String underlineToCamelCase(final String underscoreName) {
        StringBuilder result = new StringBuilder();
        if (underscoreName != null && underscoreName.trim().length() > 0) {
            boolean flag = false;
            for (int i = 0; i < underscoreName.length(); i++) {
                char ch = underscoreName.charAt(i);
                if (ConstPool.UNDERSCORE.charAt(0) == ch) {
                    flag = true;
                    continue;
                }
                if (flag) {
                    result.append(Character.toUpperCase(ch));
                    flag = false;
                } else {
                    result.append(ch);
                }
            }
        }
        return result.toString();
    }
}
